#ifndef ALGOHUB_COMMON_TYPE_20250812_H
#define ALGOHUB_COMMON_TYPE_20250812_H

#include "algohub_export.h"
#include <iostream>
#include <vector>
#include <map>
#include <array>
#include <string>
#include <iomanip> // for std::setw, std::setfill
#include <sstream> // for std::stringstream
#include <tuple> // for std::tie

namespace algobase
{
	enum AreaType
	{
		AT_Mandatory, // must
		AT_Restricted, // forbidden
		AT_Obstacle, // obs
		AT_TerrSea, // sea
		AT_ContiZone, // continental zone
	};

	enum EvaluateL1IndexType
	{
		EL1IT_Safety = 0,
		EL1IT_Stealth,
		EL1IT_Economy,
		EL1IT_Completion,
		EL1IT_Count, //  make last always
	};

	enum EvaluateL2IndexType
	{
		EL2IT_0Topography = 0, // depth
		EL2IT_1EnvironmentalNoise, // wind, rain, ship
		EL2IT_2Turbulence, // cs
		EL2IT_3CPCD, // sonar, sound Field
		EL2IT_4AcousticStealth, // 
		EL2IT_5SensorStealth, // 
		EL2IT_6NavigationDistance, // 
		EL2IT_7NavigationTime, // 
		EL2IT_8NavigationEnergy, // 
		EL2IT_9EndPointCompletion, // 
		EL2IT_10TimeCompletion, // 
		EL2IT_11MandatoryAreaCompletion, // 
		EL2IT_12HardRestriction, // depth, task config
		EL2IT_13Motivation, // platform
		EL2IT_14DangerousAreaExposure, // Dangerous Area Exposure
		EL2IT_Count, // make last always
	};

	enum EvaluateEnvirDataType
	{
		EEDT_Depth = 0, // depth
		EEDT_Wind, // wind speed
		EEDT_Rain, // rain intensity
		EEDT_ShipNoise, // ship noise
		EEDT_CS_UO, // CS Uo data
		EEDT_CS_VO, // CS Vo data
		EEDT_Sonar, // sonar data
		EEDT_Platform, // platform data
		EEDT_AreaSound, // area sound field data
	};

	enum DateType
	{
		DT_Year = 0,
		DT_Month,
		DT_Day,
	};

	using Coord = std::array<double, 2>; // lon lat
	using CoordZ = std::array<double, 3>; // lon lat depth

	using Polygon = std::vector<Coord>; // point size must be >= 3, closed polygon
	using Polygons = std::vector<Polygon>;
	using PolygonMutiTypes = std::map<AreaType, Polygons>;

	using EvaluateIndexWeightDataType = double;
	using EvaluateL2IndexTypeWeightPair = std::pair<EvaluateL2IndexType, EvaluateIndexWeightDataType>;
	using EvaluateL2IndexWeightArray = std::array<EvaluateL2IndexTypeWeightPair, EvaluateL2IndexType::EL2IT_Count>;
	using EvaluateL2IndexWeightVector = std::vector<EvaluateL2IndexTypeWeightPair>;
	using EvaluateL1IndexWeightPair = std::pair<EvaluateIndexWeightDataType, EvaluateL2IndexWeightVector>;
	using EvaluateL1IndexMap = std::map<EvaluateL1IndexType, EvaluateL1IndexWeightPair>;

	using EvaluatorL1CoordValueResult = std::array<EvaluateIndexWeightDataType, EvaluateL1IndexType::EL1IT_Count>;
	using EvaluatorL2CoordValueResult = std::array<EvaluateIndexWeightDataType, EvaluateL2IndexType::EL2IT_Count>;
	using EvaluatorL2PathRawValueResult = std::map<EvaluateL2IndexType, EvaluateIndexWeightDataType>;

	// Path self
	struct PathCoord
	{
		CoordZ mCoordZ;
		double mHeading;
		double mSpeed;

		PathCoord()
		{
			mCoordZ[0] = 0.0; // longitude
			mCoordZ[1] = 0.0; // latitude
			mCoordZ[2] = 0.0; // depth
			mHeading = 0.0; // heading
			mSpeed = 0.0; // speed
		}

		void Assign(const PathCoord& other)
		{
			mCoordZ = other.mCoordZ;
			mHeading = other.mHeading;
			mSpeed = other.mSpeed;
		}
	};

	// Evaluate the module's waypoint parameter struct separately
	struct EvaluateModuleCoord : public PathCoord
	{
		double mResult;
		double mRawValue;
		EvaluateModuleCoord() : PathCoord()
		{
			mResult = 0.0; // result of the evaluation module
			mRawValue = 0.0; // raw value of the evaluation module
		}
	};

	// The evaluator's waypoint parameter structure
	struct EvaluatorCoord : public PathCoord
	{
		double mResult;
		EvaluatorL1CoordValueResult mL1EvaIndexArray;
		EvaluatorL2CoordValueResult mL2EvaIndexArray;
		EvaluatorL2PathRawValueResult mL2RawValueMap;

		EvaluatorCoord() : PathCoord()
		{
			mResult = 0.0; // result of all evaluations
			mL1EvaIndexArray.fill(0.0); // L1 evaluation index array
			mL2EvaIndexArray.fill(0.0); // L2 evaluation index array
		}
	};

	struct TrajectoryCoord : public EvaluatorCoord
	{
		double mTime = 0.0; //Momentary Time
		double tTime = 0.0; //Total Time
		double mDistance = 0.0; //Momentary distance
		double tDistance = 0.0; //Total distance
		std::string cTime;  // timestamp
		TrajectoryCoord() : EvaluatorCoord()
		{
			mTime = 0.0; // time offset to start time
			tTime = 0.0;
			mDistance = 0.0;
			tDistance = 0.0;
		    cTime = "00";
		}
	};
	
	struct FinalPathScore
	{
		std::vector<TrajectoryCoord> TrajectoryCoords;
		double Score;
		double SafetyScore;
		double StealthScore;
		double EconomyScore;
		double CompletionScore;
		double PathTime;
		double PathDistance;
		double aSpeed;
		int DangerousNums;//Number of Dangerous Area Transits
		double DangerousTime;
		double CPCD;
		double Smoothness;
		double fuelConsumption;
		FinalPathScore()
		{
			Score = 0.0;
			SafetyScore = 0.0;
			StealthScore = 0.0;
			EconomyScore = 0.0;
			CompletionScore = 0.0;
			PathTime = 0.0;
			PathDistance = 0.0;
			aSpeed = 0.0;
			DangerousNums = 0;//Number of Dangerous Area Transits
			DangerousTime = 0.0;
			CPCD = 0.0;
			Smoothness = 0.0;
			fuelConsumption = 0.0;
		}
	};

	using Path = std::vector<PathCoord>;
	using Paths = std::vector<Path>;
	using EvaluatorCoords = std::vector<EvaluatorCoord>;
	using EvaluateModuleCoords = std::vector<EvaluateModuleCoord>;
	using TrajectoryCoords = std::vector<TrajectoryCoord>;

	struct Date
	{
		int mYear;
		int mMonth;
		int mDay;
		int mHour;

		Date()
		{
			mYear = 2024;
			mMonth = 6;
			mDay = 1;
			mHour = 0;
		}

		Date(int y, int m, int d, int h = 0)
		{
			mYear = y;
			mMonth = m;
			mDay = d;
			mHour = h;
		}

		std::string to_string() const
		{
			std::stringstream ss;
			ss << mYear 
				<< std::setw(2) << std::setfill('0') << mMonth 
				<< std::setw(2) << std::setfill('0') << mDay;
			return ss.str();
		}

		bool operator<(const Date& other) const
		{
			return std::tie(mYear, mMonth, mDay, mHour) 
				< std::tie(other.mYear, other.mMonth, other.mDay, other.mHour);
		}
	};

	struct TaskConfig
	{
		double mMinLatitude, mMaxLatitude, mMinLongitude, mMaxLongitude;
		Date mStartTime, mEndTime;
		PolygonMutiTypes mTypePolygons;
		Coord mStartPos, mEndPos;
		DateType mDateType;

		TaskConfig()
		{
			mMinLatitude = 0.0;
			mMaxLatitude = 0.0;
			mMinLongitude = 0.0;
			mMaxLongitude = 0.0;
			mStartTime = Date();
			mDateType = DT_Month;
			mEndTime = Date();
			mStartPos = { 0.0, 0.0 };
			mEndPos = { 0.0, 0.0 };
		}
	};

	struct NSGAParams
	{
		double mCrossoverRate;
		double mMutationRate;
		double mSelectionPressure;
		unsigned long long mMaxGenerations;

		NSGAParams()
		{
			mCrossoverRate = 0.9; // Crossover rate
			mMutationRate = 0.1; // Mutation rate
			mSelectionPressure = 2.0; // Selection pressure
			mMaxGenerations = 100; // Maximum number of generations
		}
	};
}

#endif // !ALGOHUB_COMMON_TYPE_20250812_H
